#include "glCanvas.h"

// Included files for OpenGL Rendering
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

#include "glCanvas.h"
#include "argparser.h"
#include "camera.h"
#include "cloth.h"
#include "fluid.h"
#include "matrix.h"
#include "tgaload.h"
#include "mesh.h"
#include "edge.h"
#include "triangle.h"
#include<map>


using namespace std;
// ========================================================
// static variables of GLCanvas class

// State of the mouse cursor
int GLCanvas::mouseButton;
int GLCanvas::mouseX;
int GLCanvas::mouseY;
int GLCanvas::curmouseX;
int GLCanvas::curmouseY;
int GLCanvas::display_list_index;
bool bladestate = 0;
BoundingBox initial_box;
ArgParser* GLCanvas::args;
Camera* GLCanvas::camera;
Cloth* GLCanvas::cloth;
Fluid* GLCanvas::fluid;
Mesh* GLCanvas::mesh;
bool GLCanvas::controlPressed;

//#define MAX_NO_TEXTURES 1
//#define CUBE_TEXTURE 0
GLuint texture_id[3];

void GLCanvas::Load() {
  delete cloth; 
  cloth = NULL;
  delete fluid; 
  fluid = NULL;
  if (args->cloth_file != "")
    cloth = new Cloth(args,mesh);
  if (args->fluid_file != "")
    fluid = new Fluid(args);

  //////////////////////////////////////////////MESH STUFF
  /*for(unsigned int i=0; i<cloth->nx; i++)
  {
	for(unsigned int j=0; j<cloth->ny; j++)
	{
		mesh->addVertex(cloth->getParticle(i,j).getPosition());
		//cloth->getParticle(i,j).myVertex = mesh->getVertex(mesh->numVertices()-1);
		//mesh->getVertex(mesh->numVertices()-1);
	}
  }
  cout<<"Number of Vertices: "<<mesh->numVertices()<<endl;*/
  //mesh->
  
  //////////////////////////////////////////////MESH STUFF
}

// ========================================================
// Initialize all appropriate OpenGL variables, set
// callback functions, and start the main event loop.
// This function will not return but can be terminated
// by calling 'exit(0)'
// ========================================================

void GLCanvas::initialize(ArgParser *_args,Mesh *_mesh) {
	//lastX= -1;
	//lastY= -1;
  args = _args;
  mesh=_mesh;
  cloth = NULL;
  fluid = NULL;
  Load();
  Vec3f camera_position = Vec3f(0,0,4);
  Vec3f point_of_interest = Vec3f(0,0,0);
  Vec3f up = Vec3f(0,1,0);
  camera = new PerspectiveCamera(camera_position, point_of_interest, up, 20 * M_PI/180.0);

  // setup glut stuff
  glutInitWindowSize(args->width, args->height);
  glutInitWindowPosition(100,100);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);
  glutCreateWindow("OpenGL Viewer");

  // basic rendering 
  glEnable(GL_LIGHTING);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  glShadeModel(GL_SMOOTH);
  glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
  GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 };
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  glCullFace(GL_BACK);
  glDisable(GL_CULL_FACE);

  display_list_index = glGenLists(1);
  
  
  /////////////////////////////////// TEXTURE
  
   glEnable ( GL_COLOR_MATERIAL );
   glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );

	glEnable ( GL_TEXTURE_2D );
   glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
   glGenTextures (3, texture_id);

   image_t   temp_image;

   glBindTexture ( GL_TEXTURE_2D, texture_id[0]);//[CUBE_TEXTURE] );
   if (args->blade == "scalpel")
      tgaLoad  ( "scalpel1.tga", &temp_image, TGA_FREE );//| TGA_LOW_QUALITY );
   else if (args->blade == "katana")
        tgaLoad  ( "katana1.tga", &temp_image, TGA_FREE );//| TGA_LOW_QUALITY );
   glBindTexture ( GL_TEXTURE_2D, texture_id[1]);//[CUBE_TEXTURE] );
   if (args->blade == "scalpel")
      tgaLoad  ( "scalpel2.tga", &temp_image, TGA_FREE );//| TGA_LOW_QUALITY );
   else if (args->blade == "katana")
        tgaLoad  ( "katana2.tga", &temp_image, TGA_FREE );
   glBindTexture ( GL_TEXTURE_2D, texture_id[2]);//[CUBE_TEXTURE] );
   tgaLoad  ( "cloth.tga", &temp_image, TGA_FREE );//| TGA_LOW_QUALITY );
   //glEnable ( GL_CULL_FACE );
   glBindTexture (GL_TEXTURE_2D, texture_id[0]);
   /////////////////////////////////////////////////////

  // Initialize callback functions
  glutMouseFunc(mouse);
  glutSetCursor(GLUT_CURSOR_NONE);
  glutMotionFunc(motion);
  glutDisplayFunc(display);
  glutPassiveMotionFunc(SmoothMotion);
  glutReshapeFunc(reshape);
  glutKeyboardFunc(keyboard);
  glutIdleFunc(idle);
  
  glEnable(GL_BLEND);
  glColor4f(1.0f, 1.0f, 1.0f, 0.5);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  //glColor4f(1.0,1.0,1.0,1);
  //glDisable(GL_BLEND);
  Render();
 // display();
 
 initial_box = cloth->getBoundingBox();


  // Enter the main rendering loop
  glutMainLoop();
}

// ========================================================

void GLCanvas::InitLight() {
  // Set the last component of the position to 0 to indicate
  // a directional light source

  GLfloat position[4] = { 30,30,100,1};//100, 1};
  GLfloat diffuse[4] = { 0.75,0.75,0.75,1};
  GLfloat specular[4] = { 0,0,0,1};
  GLfloat ambient[4] = { 0.2, 0.2, 0.2, 1.0 };

  GLfloat zero[4] = {0,0,0,0};
  glLightfv(GL_LIGHT1, GL_POSITION, position);
  glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
  glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
  glLightfv(GL_LIGHT1, GL_AMBIENT, zero);
  glEnable(GL_LIGHT1);
  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  glEnable(GL_COLOR_MATERIAL);
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);

  GLfloat spec_mat[4] = {1,1,1,1};
  float glexponent = 30;
  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &glexponent);
  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec_mat);

  glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  float back_color[] = {1.0,1.0,1.0,1};//{ 0.5,0.5,1.0,1};
  glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, back_color);
  glEnable(GL_LIGHT1);
}

void GLCanvas::display(void)
{
     //std::cout << "display() " << std::endl;
  // Clear the display buffer, set it to the background color
  glClearColor(1,1,1,0);
  
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Set the camera parameters
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  InitLight(); // light will be a headlamp!
  camera->glPlaceCamera();
  
    glDisable(GL_BLEND); 
  
  //std::cout << "painted cloth" << std::endl;
  //if (cloth) cloth->Paint();
  glDisable(GL_TEXTURE_2D);
  Render();
  glEnable(GL_TEXTURE_2D);
  //glColor4f(1.0,1.0,1.0,1);
  //glDisable(GL_BLEND);
  //Render();
  
  //glColor4f(10.0,10.0,10.0,1);
  glEnable(GL_BLEND); 
  glColor4f(1.0, 1.0, 1.0,1);
  if (bladestate == 0) glBindTexture ( GL_TEXTURE_2D, texture_id[0] );
  else glBindTexture ( GL_TEXTURE_2D, texture_id[1] );
    glBegin(GL_QUADS);						
    float tempx = curmouseX * (2.0 / 500.0) - 1.0;
   float tempy = curmouseY * (2.0 / 500.0) - 1.0;
   
   //std::cout << "TEMPx = " << tempx << " TEMPy = " << tempy << std::endl;
     
     glTexCoord2f(1.0f, 0.0f);glVertex3f(tempx+0.2f,-tempy-0.0f,0.5f);
     glTexCoord2f(1.0f, 1.0f);glVertex3f(tempx+0.2f,-tempy+0.4f,0.5f);
     glTexCoord2f(0.0f, 1.0f);glVertex3f(tempx-0.0f,-tempy+0.4f,0.5f);
     glTexCoord2f(0.0f, 0.0f);glVertex3f(tempx-0.0f,-tempy-0.0f,0.5f);
     /*glTexCoord2f(0.0f, 0.0f);glVertex3f(tempx-0.0f,-tempy-0.0f,-0.0f);
     glTexCoord2f(0.0f, 1.0f);glVertex3f(tempx-0.0f,-tempy+0.4f,-0.0f);
     glTexCoord2f(1.0f, 1.0f);glVertex3f(tempx+0.2f,-tempy+0.4f,-0.0f);
     glTexCoord2f(1.0f, 0.0f);glVertex3f(tempx+0.2f,-tempy-0.0f,-0.0f);*/
     /*glTexCoord2f(0.0f, 0.0f);glVertex2d(tempx-0.0f,-tempy-0.0f);
     glTexCoord2f(0.0f, 1.0f);glVertex2d(tempx-0.0f,-tempy+0.4f);
     glTexCoord2f(1.0f, 1.0f);glVertex2d(tempx+0.2f,-tempy+0.4f);
     glTexCoord2f(1.0f, 0.0f);glVertex2d(tempx+0.2f,-tempy-0.0f);*/
     
	glEnd();


  glEnable(GL_LIGHTING);
  glEnable(GL_DEPTH_TEST);
  
  glCallList(display_list_index);
  HandleGLError(); 
   
  // Swap the back buffer with the front buffer to display
  // the scene
  glColor4f( 1,1,1,1);
  glutSwapBuffers();
}

// ========================================================
// Callback function for window resize
// ========================================================

void GLCanvas::reshape(int w, int h) {
  // Set the OpenGL viewport to fill the entire window
  glViewport(0, 0, (GLsizei)w, (GLsizei)h);

  // Set the camera parameters to reflect the changes
  camera->glInit(w, h);




  args->width = w;
  args->height = h;
}

// ========================================================
// Callback function for mouse click or release
// ========================================================

void GLCanvas::mouse(int button, int state, int x, int y) {
  // Save the current state of the mouse.  This will be
  // used by the 'motion' function
  mouseButton = button;
  //std::cout << "lol" << std::endl;
  mouseX = x;
  mouseY = y;
  controlPressed = glutGetModifiers() & GLUT_ACTIVE_CTRL;
  if (mouseButton == GLUT_LEFT_BUTTON) 
  { 
    if (state == GLUT_DOWN) 
    { 
              glBindTexture (GL_TEXTURE_2D, texture_id[1]);
              bladestate = 1;
    }
    else if (state == GLUT_UP) { glBindTexture (GL_TEXTURE_2D, texture_id[0]); bladestate = 0;}
    display();
  }
}

void GLCanvas::SmoothMotion(int x, int y)
{
     curmouseX = x;
     curmouseY = y;
     display(); 
     //glutPostRedisplay();
}

void GLCanvas::cutCloth(ClothParticle& cp, int i, int j, bool topEdge, bool bottomEdge, bool leftEdge, bool rightEdge, int direction, \
 bool topLeft, bool topRight, bool bottomLeft, bool bottomRight)
{
	//direction 0: vertical, downwards
	//direction 1: vertical, upwards
	//direction 2: horiz from left
	//direction 3: horiz from right
	//cout<<"er1 i: "<<i<<" j: "<<j<<endl;
	/*if(j+1 < cloth->ny)
	{
		Vertex *va = cloth->getParticle(i,j).vert;
		Vertex *vb = cloth->getParticle(i,j+1).vert;//mesh->getVertex(i*cloth->nx+j+1);
		Edge *ab = mesh->getMeshEdge(va,vb);
		if(ab)
		{
			
			Triangle *t = ab->getTriangle();
			if(t)
			{
				mesh->removeTriangle(t);
			}
		}
	}
	else
		return;*/
	//cout<<"lol1"<<endl;
	//if(j+1 >= cloth->ny) return;	
	//edges.erase(std::make_pair(a,b)); 
	if(topLeft || topRight || bottomLeft || bottomRight)
	{
		if(topLeft && i-1>=0 && j-1>=0)
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i-1,j-1).vert ) );
		else if(topRight && i-1>=0 && j+1<cloth->ny)
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i-1,j+1).vert ) );
		else if(bottomLeft && i+1<cloth->nx && j-1>=0)
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i+1,j-1).vert ) );
		else if(i+1<cloth->nx && j+1<cloth->ny)
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i+1,j+1).vert ) );
		
	}
	else
	{
		if(direction==0 && i+1<cloth->nx)
		{
			//mesh->removeTriangle( mesh->getMeshEdge(cloth->getParticle(i,j).vert,cloth->getParticle(i+1,j).vert )->getTriangle() );
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i+1,j).vert ) );
			cloth->getParticle(i,j).vert->cutRight=true; cloth->getParticle(i+1,j).vert->cutLeft=true;
			//Vertex *a = mesh->addVertex(cloth->getParticle(i,j).getPosition());
			//a->relationshipParticle = &(cloth->getParticle(i,j));
			//mesh->addTriangle(a,cloth->getParticle(i,j).vert,cloth->getParticle(i+1,j).vert);
			
		}
		else if(direction==1 && i-1>=0)
		{
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i-1,j).vert ) );
			cloth->getParticle(i,j).vert->cutLeft=true; cloth->getParticle(i-1,j).vert->cutRight=true;
		}
		else if(direction==2 &&j-1>=0)
		{
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i,j-1).vert ) );
			cloth->getParticle(i,j).vert->cutUp=true; cloth->getParticle(i,j-1).vert->cutDown=true;
		}
		else if(direction==3 &&j+1<cloth->ny)
		{
			mesh->edges.erase(make_pair( cloth->getParticle(i,j).vert, cloth->getParticle(i,j+1).vert ) );	
			cloth->getParticle(i,j).vert->cutDown=true; cloth->getParticle(i,j+1).vert->cutUp=true;
		}
	}
	
	//return; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	if(i>=0 && i<cloth->nx-1 && j>=0 && j<cloth->ny)//( i > 0 && i+1 < cloth->nx && j > 0 && j+1 < cloth->ny )
	{
		Vertex *vS,*vR,*vL,*vU,*vD,*vUL,*vUR,*vDL,*vDR = NULL;
		
		vS = cloth->getParticle(i,j).vert; //spot
		if(j+1 < cloth->ny)
			vR = cloth->getParticle(i,j+1).vert; //right
		if(j-1 >= 0)
			vL = cloth->getParticle(i,j-1).vert; //left
		if(i-1 >= 0)
		{
			vU = cloth->getParticle(i-1,j).vert; //up
		}
		if(i+1 < cloth->nx)
			vD = cloth->getParticle(i+1,j).vert; //down
		if(i-1 >= 0 && j-1 >= 0)
			vUL = cloth->getParticle(i-1,j-1).vert; //upleft
		if(i-1 >=0 && j+1 < cloth->ny)
			vUR = cloth->getParticle(i-1,j+1).vert; //upright
		if(i+1 < cloth->nx && j-1 >= 0)
			vDL = cloth->getParticle(i+1,j-1).vert; //downleft
		if(i+1 < cloth->nx && j+1 < cloth->ny)
			vDR = cloth->getParticle(i+1,j+1).vert; //downright
		
		Edge *left,*right,*up,*down,*upleft,*upright,*downleft,*downright = NULL;
		
		if(vL)
		{
			left = mesh->getMeshEdge(vS,vL);
			//if(left == NULL) return;
		}
		if(vR)
		{
			right = mesh->getMeshEdge(vS,vR);
			//if(right == NULL) return;
		}
		if(vU)
		{
			up = mesh->getMeshEdge(vS,vU); 
			//if(up == NULL) return;
		}
		if(vD)
		{
			down = mesh->getMeshEdge(vS,vD);
			//if(down == NULL) return;
		}
		
		if(vUL && vU!=NULL)
		{
			upleft = mesh->getMeshEdge(vU,vUL);
			//if(upleft == NULL) return;
		}
		if(vUR && vU!=NULL)
		{
			upright = mesh->getMeshEdge(vU,vUR);
			//if(upright == NULL) return;
		}
		if(vDL && vD!=NULL)
		{
			downleft = mesh->getMeshEdge(vD,vDL);
			//if(downleft == NULL) return;
		}
		if(vDR && vD!=NULL)
		{
			downright = mesh->getMeshEdge(vD,vDR);
			//if(downright == NULL) return;
		}
		
		vector<pair<int, int> > vStruc = cloth->getParticle(i,j).struc;
		vector<pair<int, int> > vShear = cloth->getParticle(i,j).shear;
		vector<pair<int, int> > vBend = cloth->getParticle(i,j).bend;
		
		if(!left && vL)
		{
			if(i-1 >= 0)
				for(unsigned int ii=0; ii<vStruc.size(); ii++)
				{
					if(vStruc[ii].first == i-1 && vStruc[ii].second == j)
					{
						vector<pair<int, int> > v2Struc = cloth->getParticle(i-1,j).struc;
						for(unsigned int jj=0; jj<v2Struc.size(); jj++)
						{
							if(v2Struc[jj].first == i && v2Struc[jj].second == j)
							{
								cloth->getParticle(i-1,j).struc.erase(cloth->getParticle(i-1,j).struc.begin()+jj); //v2Struc.erase(v2Struc.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+ii);//vStruc.erase(vStruc.begin()+ii);
						break;
					}
				}
			if(i-2 >= 0)
				for(unsigned int ii=0; ii<vBend.size(); ii++)
				{
					if(vBend[ii].first == i-2 && vBend[ii].second == j)
					{
						vector<pair<int, int> > v2Bend = cloth->getParticle(i-2,j).bend;
						for(unsigned int jj=0; jj<v2Bend.size(); jj++)
						{
							if(v2Bend[jj].first == i && v2Bend[jj].second == j)
							{
								cloth->getParticle(i-2,j).bend.erase(cloth->getParticle(i-2,j).bend.begin()+jj); //v2Bend.erase(v2Bend.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).bend.erase(cloth->getParticle(i,j).bend.begin()+ii); //vBend.erase(vBend.begin()+ii);
						break;
					}
				}
		}
		if(!right && vR)
		{
			if(i+1 < cloth->nx)
				for(unsigned int ii=0; ii<vStruc.size(); ii++)
				{
					if(vStruc[ii].first == i+1 && vStruc[ii].second == j)
					{
						vector<pair<int, int> > v2Struc = cloth->getParticle(i+1,j).struc;
						for(unsigned int jj=0; jj<v2Struc.size(); jj++)
						{
							if(v2Struc[jj].first == i && v2Struc[jj].second == j)
							{
								cloth->getParticle(i+1,j).struc.erase(cloth->getParticle(i+1,j).struc.begin()+jj);//v2Struc.erase(v2Struc.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+ii);//vStruc.erase(vStruc.begin()+ii);
						break;
					}
				}
			if(i+2 < cloth->nx)
				for(unsigned int ii=0; ii<vBend.size(); ii++)
				{
					if(vBend[ii].first == i+2 && vBend[ii].second == j)
					{
						vector<pair<int, int> > v2Bend = cloth->getParticle(i+2,j).bend;
						for(unsigned int jj=0; jj<v2Bend.size(); jj++)
						{
							if(v2Bend[jj].first == i && v2Bend[jj].second == j)
							{
								cloth->getParticle(i+2,j).bend.erase(cloth->getParticle(i+2,j).bend.begin()+jj); //v2Bend.erase(v2Bend.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).bend.erase(cloth->getParticle(i,j).bend.begin()+ii);//vBend.erase(vBend.begin()+ii);
						break;
					}
				}
		}
		if(!up && vU)
		{
			if(j-1 >= 0)
				for(unsigned int ii=0; ii<vStruc.size(); ii++)
				{
					if(vStruc[ii].first == i && vStruc[ii].second == j-1)
					{
						vector<pair<int, int> > v2Struc = cloth->getParticle(i,j-1).struc;
						for(unsigned int jj=0; jj<v2Struc.size(); jj++)
						{
							if(v2Struc[jj].first == i && v2Struc[jj].second == j)
							{
								cloth->getParticle(i,j-1).struc.erase(cloth->getParticle(i,j-1).struc.begin()+jj);//v2Struc.erase(v2Struc.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+ii);//vStruc.erase(vStruc.begin()+ii);
						break;
					}
				}
			if(j-2 >= 0)
				for(unsigned int ii=0; ii<vBend.size(); ii++)
				{
					if(vBend[ii].first == i && vBend[ii].second == j-2)
					{
						vector<pair<int, int> > v2Bend = cloth->getParticle(i,j-2).bend;
						for(unsigned int jj=0; jj<v2Bend.size(); jj++)
						{
							if(v2Bend[jj].first == i && v2Bend[jj].second == j)
							{
								cloth->getParticle(i,j-2).bend.erase(cloth->getParticle(i,j-2).bend.begin()+jj); //v2Bend.erase(v2Bend.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).bend.erase(cloth->getParticle(i,j).bend.begin()+ii); //vBend.erase(vBend.begin()+ii);
						break;
					}
				}
		}
		if(!down && vD)
		{
			if(j+1 < cloth->ny)
				for(unsigned int ii=0; ii<vStruc.size(); ii++)
				{
					if(vStruc[ii].first == i && vStruc[ii].second == j+1)
					{
						vector<pair<int, int> > v2Struc = cloth->getParticle(i,j+1).struc;
						for(unsigned int jj=0; jj<v2Struc.size(); jj++)
						{
							if(v2Struc[jj].first == i && v2Struc[jj].second == j)
							{
								cloth->getParticle(i,j+1).struc.erase(cloth->getParticle(i,j+1).struc.begin()+jj);//v2Struc.erase(v2Struc.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+ii);//vStruc.erase(vStruc.begin()+ii);
						break;
					}
				}
			if(j+2 < cloth->ny)
				for(unsigned int ii=0; ii<vBend.size(); ii++)
				{
					if(vBend[ii].first == i && vBend[ii].second == j+2)
					{
						vector<pair<int, int> > v2Bend = cloth->getParticle(i,j+2).bend;
						for(unsigned int jj=0; jj<v2Bend.size(); jj++)
						{
							if(v2Bend[jj].first == i && v2Bend[jj].second == j)
							{
								cloth->getParticle(i,j+2).bend.erase(cloth->getParticle(i,j+2).bend.begin()+jj); //v2Bend.erase(v2Bend.begin()+jj);
								break;
							}
						}
						cloth->getParticle(i,j).bend.erase(cloth->getParticle(i,j).bend.begin()+ii); //vBend.erase(vBend.begin()+ii);
						break;
					}
				}
		}
		
		
		return;
		
		
		if(!upleft && vUL)
		{
			for(unsigned int ii=0; ii<vShear.size(); ii++)
			{
				if(vShear[ii].first == i-1 && vShear[ii].second == j-1)
				{
					vector<pair<int, int> > v2Shear = cloth->getParticle(i-1,j-1).shear;
					for(unsigned int jj=0; jj<v2Shear.size(); jj++)
					{
						if(v2Shear[jj].first == i && v2Shear[jj].second == j)
						{
							//cloth->getParticle(i-1,j-1).shear.erase(cloth->getParticle(i-1,j-1).shear.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
							break;
						}
					}
					cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+ii); //vShear.erase(vShear.begin()+ii);
					break;
				}
			}
		}
		if(!upright && vUR)
		{
			for(unsigned int ii=0; ii<vShear.size(); ii++)
			{
				if(vShear[ii].first == i-1 && vShear[ii].second == j+1)
				{
					vector<pair<int, int> > v2Shear = cloth->getParticle(i-1,j+1).shear;
					for(unsigned int jj=0; jj<v2Shear.size(); jj++)
					{
						if(v2Shear[jj].first == i && v2Shear[jj].second == j)
						{
							//cloth->getParticle(i-1,j+1).shear.erase(cloth->getParticle(i-1,j+1).shear.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
							break;
						}
					}
					cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+ii); //vShear.erase(vShear.begin()+ii);
					break;
				}
			}
		}
		if(!downleft && vDL)
		{
			for(unsigned int ii=0; ii<vShear.size(); ii++)
			{
				if(vShear[ii].first == i+1 && vShear[ii].second == j-1)
				{
					vector<pair<int, int> > v2Shear = cloth->getParticle(i+1,j-1).shear;
					for(unsigned int jj=0; jj<v2Shear.size(); jj++)
					{
						if(v2Shear[jj].first == i && v2Shear[jj].second == j)
						{
							//cloth->getParticle(i+1,j-1).shear.erase(cloth->getParticle(i+1,j-1).shear.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
							break;
						}
					}
					cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+ii); //vShear.erase(vShear.begin()+ii);
					break;
				}
			}
		}
		if(!downright && vDR)
		{
			for(unsigned int ii=0; ii<vShear.size(); ii++)
			{
				if(vShear[ii].first == i+1 && vShear[ii].second == j+1)
				{
					vector<pair<int, int> > v2Shear = cloth->getParticle(i+1,j+1).shear;
					for(unsigned int jj=0; jj<v2Shear.size(); jj++)
					{
						if(v2Shear[jj].first == i && v2Shear[jj].second == j)
						{
							//cloth->getParticle(i+1,j+1).shear.erase(cloth->getParticle(i+1,j+1).shear.begin()+jj); //v2Shear.erase(v2Shear.begin()+jj);
							break;
						}
					}
					cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+ii); //vShear.erase(vShear.begin()+ii);
					break;
				}
			}
		}
		
		
		
	}
	
	
}



void GLCanvas::checkBoundingBoxes(float x,float y)
{
	//cout<<"x: "<<x<<" y: "<<y<<endl;
	//int checked=false;
	map< float, pair<int,int> > clothTouchMap;

	for(unsigned int i=0; i<cloth->nx; i++)
	{
		for(unsigned int j=0; j<cloth->ny; j++)
		{
			if(cloth->getParticle(i,j).box.checkInside(x,y)) //&& !checked)
			{
				clothTouchMap[cloth->getParticle(i,j).getZ()*-1]=make_pair(i,j);
			}
		}
	}
	
	map<float,pair<int,int> >::iterator it;
	it=clothTouchMap.begin();
	while(it!=clothTouchMap.end())
	{
		//cout<<"Z: "<<(*it).first<<endl;
		int i=(*it).second.first;
		int j=(*it).second.second;

		//checked=true;
		//cout<<"Blade is touching cloth particle i:"<<i<<" j: "<<j<<endl;
		
		Vec3f XY = Vec3f(x,y,0);
		//if(!cloth->getParticle(i,j)) break;
		ClothParticle cp = cloth->getParticle(i,j);
		
		float distA=cp.box.dist(cp.box.getTopLeft(), XY);
		float distB=cp.box.dist(cp.box.getTopRight(), XY);
		float distC=cp.box.dist(cp.box.getBottomLeft(), XY);
		float distD=cp.box.dist(cp.box.getBottomRight(), XY);
	
		/*cout<<"distA: "<<distA<<endl;
		cout<<"distB: "<<distB<<endl;
		cout<<"distC: "<<distC<<endl;
		cout<<"distD: "<<distD<<endl;*/
	
		float dist=distA;
		int counter=0;
		int k=i, l=j;
		if(dist>distB) { dist=distB; counter=1; }
		if(dist>distC) { dist=distC; counter=2; }
		if(dist>distD) { dist=distD; counter=3; }
		
		
		if(counter==1 && i+1 < cloth->nx) { cp=cloth->getParticle(i+1,j); k=i+1; }
		if(counter==2 && j+1 < cloth->ny) { cp=cloth->getParticle(i,j+1); l=j+1; }
		if(counter==3 && i+1 < cloth->nx && j+1 <cloth->ny) { cp=cloth->getParticle(i+1,j+1); k=i+1; l=j+1; }
		
		if(cp.cut)// && !cp.cut2)
		{
			bool top=false; bool bottom=false; bool left=false; bool right=false;
			bool topLeft=false; bool topRight=false; bool bottomLeft=false; bool bottomRight=false;
			
			float yDiff = cloth->getParticle(i,j).lastSpot.y() - XY.y();
			float xDiff = cloth->getParticle(i,j).lastSpot.x() - XY.x();
			int direction = 0;
			if(abs(yDiff) >= abs(xDiff)) //vertical
			{
				if(cloth->getParticle(i,j).lastSpot.y() > XY.y()) //going down
				{
					if(counter == 0 || counter == 2) { left=true; }
					else { right=true; }
				}
				else //going up
				{
					if(counter == 0 || counter == 2) { left=true; }
					else{ right=true; }
					direction=1;
				}
			}
			else //horizontal
			{
				if(cloth->getParticle(i,j).lastSpot.x() > XY.x()) //going left
				{	
					if(counter < 2) { top=true; }
					else { bottom=true; }
					direction=2;
				}
				else //going right
				{
					if(counter < 2) { top=true; }
					else{ bottom=true; }
					direction=3;
				}
			}
			
			float epsilon=0.004;
			//cout<<"yDiff: "<<yDiff<<" "<<" xDiff: "<<xDiff<<endl;
			if( abs(yDiff) < abs(xDiff)+epsilon && abs(yDiff) > abs(xDiff)-epsilon )
			{
				if(yDiff > 0) 
					if(xDiff > 0) //lastspot - newspot, positive is down and left
						bottomLeft=true;
					else
						bottomRight=true;
				else
					if(xDiff > 0)
						topLeft=true;
					else
						topRight=true;
						
				top=false; bottom=false; right=false; left=false;
			}
			
			
			//cout<<"t: "<<top<<" b: "<<bottom<<" l: "<<left<<" r: "<<right<<" tL: "<<topLeft<<" tR"<<topRight<<" bL: "<<bottomLeft\
			// <<" bR: "<<bottomRight<<endl;
			
			Vec3f cutForce=Vec3f(XY.x() - cloth->getParticle(i,j).lastSpot.x(),XY.y() - cloth->getParticle(i,j).lastSpot.y(),0.0);
			cutForce.Normalize();
			if(args->blade == "katana")
				cutForce=cutForce*7.5;
			
			//cout<<cp.getVelocity()<<endl;
			//cout<<"before cut"<<endl;
			cutCloth(cp,k,l,top, bottom, left, right, direction, topLeft, topRight, bottomLeft, bottomRight);
			//cout<<"after cut"<<endl;
			cloth->getParticle(i,j).setVelocity(cloth->getParticle(i,j).getVelocity()+cutForce);
			cloth->getParticle(i,j).cut2=true;
			//cout<<cp.getVelocity()<<endl;
		}	
		
		//if(!cp.cut)
		//{
		cloth->getParticle(i,j).cut=true;
		cloth->getParticle(i,j).lastSpot=XY;
		//}
		vector<Vertex *> verts=mesh->cleanTriangles();
		/*for(unsigned int ii=0; ii<cloth->nx; ii++)
		{
			for(unsigned int jj=0; jj<cloth->ny; jj++)
			{
				for(unsigned int kk=0; kk<verts.size(); kk++)
				{
					if(cloth->getParticle(i,j).vert == verts[kk])
					{
						cloth->getParticle(i,j).setMass(cloth->getParticle(i,j).getMass()/1.0005);
					}
				}
			}
		}*/
		it++;	
		
		/*for(unsigned int ii=0; ii<cloth->nx; ii++)
			for(unsigned int jj=0; jj<cloth->ny; jj++)
			{
				for(unsigned int kk=0; kk<verts.size(); kk++)
				{
					if(cloth->getParticle(i,j).vert == verts[kk])
					{
						cloth->getParticle(i,j).setMass(cloth->getParticle(i,j).getMass()/10);
						for(unsigned int kk2=0; kk2<verts.size(); kk2++)
						{
							if(kk2!=kk)
							{
								Edge *e = mesh->getMeshEdge(cloth->getParticle(i,j).vert,verts[kk2]);
								if(e==NULL) //edge was deleted, delete connection
								{
									vector<pair<int, int> > vStruc = cloth->getParticle(i,j).struc;
									vector<pair<int, int> > vShear = cloth->getParticle(i,j).shear;
									
									for(unsigned int kk3=0; kk3<vStruc.size(); kk3++) //go through 1st vector of struc
									{
										if(cloth->getParticle(vStruc[kk3].first,vStruc[kk3].second).vert == verts[kk2])
										{
											cloth->getParticle(i,j).struc.erase(cloth->getParticle(i,j).struc.begin()+kk3);
											vector<pair<int, int> > vStruc2 = cloth->getParticle(vStruc[kk3].first,vStruc[kk3].second).struc;
											for(unsigned int kk4=0; kk4<vStruc2.size(); kk4++) //fo through 2nd vector of struc
											{
												if(cloth->getParticle(vStruc2[kk4].first,vStruc2[kk4].second).vert == cloth->getParticle(i,j).vert)
												{
													cloth->getParticle(vStruc2[kk4].first,vStruc2[kk4].second).struc.erase(cloth->getParticle(vStruc2[kk4].first,vStruc2[kk4].second).struc.begin()+kk4);
												}
											}
										}
									}
									
									for(unsigned int kk3=0; kk3<vShear.size(); kk3++) //go through 1st vector of Shear
									{
										if(cloth->getParticle(vShear[kk3].first,vShear[kk3].second).vert == verts[kk2])
										{
											cloth->getParticle(i,j).shear.erase(cloth->getParticle(i,j).shear.begin()+kk3);
											vector<pair<int, int> > vShear2 = cloth->getParticle(vShear[kk3].first,vShear[kk3].second).shear;
											for(unsigned int kk4=0; kk4<vShear2.size(); kk4++) //fo through 2nd vector of Shear
											{
												if(cloth->getParticle(vShear2[kk4].first,vShear2[kk4].second).vert == cloth->getParticle(i,j).vert)
												{
													cloth->getParticle(vShear2[kk4].first,vShear2[kk4].second).shear.erase(cloth->getParticle(vShear2[kk4].first,vShear2[kk4].second).shear.begin()+kk4);
												}
											}
										}
									}
									
									
									
								}
							}
						}
						
						break;
					}
				}
			}*/
					
	}
}




// ========================================================
// Callback function for mouse drag
// ========================================================

void GLCanvas::motion(int x, int y) {
  // Left button = rotation
  // (rotate camera around the up and horizontal vectors)
  if (mouseButton == GLUT_LEFT_BUTTON) {
    //camera->rotateCamera(0.005*(mouseX-x), 0.005*(mouseY-y));
    mouseX = x;
    mouseY = y;
    curmouseX = x;
    curmouseY = y;
	
	float tempx = curmouseX * (2.0 / 500.0) - 1.0;
    float tempy = curmouseY * (2.0 / 500.0) - 1.0;
    float xx=tempx+0.15f; 
	float yy=-tempy+0.35f;
	//std::cout<<"X: "<<x<<" Y: "
	//std::cout<<"xx: "<<xx<<" yy: "<<yy<<endl;
	GLCanvas::checkBoundingBoxes(xx,yy);
	//GLCanvas::lastX=xx;
	//GLCanvas::lastY=yy;
	
  }
  // Middle button = translation
  // (move camera perpendicular to the direction vector)
  else if (mouseButton == GLUT_MIDDLE_BUTTON) {
    //camera->truckCamera((mouseX-x)*0.5, (y-mouseY)*0.5);
    camera->rotateCamera(0.005*(mouseX-x), 0.005*(mouseY-y));
    mouseX = x;
    mouseY = y;
    curmouseX = x;
    curmouseY = y;
    //std::cout << "middle button!!" << std::endl;
    //[CUBE_TEXTURE] ); }

  }
  // Right button = dolly or zoom
  // (move camera along the direction vector)
  else if (mouseButton == GLUT_RIGHT_BUTTON) {
    if (controlPressed) {
      camera->zoomCamera(mouseY-y);
    } else {
      camera->dollyCamera(mouseY-y);
    }
    mouseX = x;
    mouseY = y;
    curmouseX = x;
    curmouseY = y;
  }
  
    if (args->animate) {
    // do 10 steps of animation before rendering
    for (int i = 0; i < 10; i++) {
      if (cloth) cloth->Animate();
      }
    }
  // Redraw the scene with the new camera parameters
  display();
  //glutPostRedisplay();
}

// ========================================================
// Callback function for keyboard events
// ========================================================

void GLCanvas::keyboard(unsigned char key, int x, int y) {
  switch (key) {
  case 'a': case 'A':
    // toggle continuous animation
    args->animate = !args->animate;
    if (args->animate) 
      printf ("animation started, press 'A' to stop\n");
    else
      printf ("animation stopped, press 'A' to start\n");
    break;
  case ' ':
    // a single step of animation
    if (cloth) cloth->Animate();
    if (fluid) fluid->Animate();
     display();//Render();
    break; 
  case 'm':  case 'M': 
    args->particles = !args->particles;
    display();//Render();
    break; 
  case 'v':  case 'V': 
    args->velocity = !args->velocity;
    display();//Render();
    break; 
  case 'f':  case 'F': 
    args->force = !args->force;
    display();//Render();
    break; 
  case 'e':  case 'E': 
    args->edge_velocity = (args->edge_velocity+1)%4;
    display();//Render();
    break; 
  case 'd':  case 'D': 
    args->dense_velocity = (args->dense_velocity+1)%4;
    display();//Render();
    break; 
  case 's':  case 'S': 
    args->surface = !args->surface;
    display();//Render();
    break; 
  case 'w':  case 'W':
    args->wireframe = !args->wireframe;
    display();//Render();
    break;
  case 'b':  case 'B':
    args->bounding_box = !args->bounding_box;
    display();//Render();
    break;
  case 'c':  case 'C': 
    args->cubes = !args->cubes;
    display();//Render();
    break; 
  case 'p':  case 'P': 
    args->pressure = !args->pressure;
    display();//Render();
    break; 
  case 'r':  case 'R': 
    // reset system
    Load();
    display();//Render();
    break; 
  case '+': case '=':
    args->isosurface += 0.1;
    if (args->isosurface >= 0.999) args->isosurface = 0.99;
    printf ("isosurface %f\n", args->isosurface);
    display();//Render();
    break;
  case '-': case '_':
    args->isosurface -= 0.1;
    if (args->isosurface <= 0.001) args->isosurface = 0.01;
    printf ("isosurface %f\n", args->isosurface);
    display();//Render();
    break;
  case 'q':  case 'Q':
    delete cloth;
    cloth = NULL;
    delete fluid;
    fluid = NULL;
    delete args;
    args = NULL;
    delete camera;
    camera = NULL;
    printf ("program exiting\n");
    exit(0);
    break;
  default:
    printf("UNKNOWN KEYBOARD INPUT  '%c'\n", key);
  }
}


void GLCanvas::idle() {
  if (args->animate) {
    // do 10 steps of animation before rendering
    for (int i = 0; i < 10; i++) {
      if (cloth) cloth->Animate();
      if (fluid) fluid->Animate();
    }
    display();//Render();
  }
 
}

void GLCanvas::Render2() 
{
  //HandleGLError();
  //glNewList(display_list_index, GL_COMPILE_AND_EXECUTE);
  // =========================================================
  // put your GL drawing calls inside the display list for efficiency
  mesh->Paint(args,curmouseX,curmouseY,texture_id[2]);
  // =========================================================
  //glEndList();
  //glutPostRedisplay();
  //HandleGLError();
}

void GLCanvas::Render() {
  //glNewList(display_list_index, GL_COMPILE_AND_EXECUTE);
  // =========================================================
  // put your GL drawing calls inside the display list for efficiency

  glMatrixMode(GL_MODELVIEW);
	Render2();
  BoundingBox box;
  if (fluid != NULL) {
    box = fluid->getBoundingBox();
    if (cloth != NULL) {
      box.Extend(cloth->getBoundingBox());
    }
  } else {
    assert (cloth != NULL);
    box = cloth->getBoundingBox(); 
  }
  
  // center the volume in the window
  Matrix m;
  m.SetToIdentity();
  Vec3f center = initial_box.getCenter();
  m *= Matrix::MakeScale(1/float(initial_box.maxDim()));
  m *= Matrix::MakeTranslation(-center); 
  glMultMatrixf(m.glGet());
  
  glDisable(GL_BLEND); 
  glColor4f(2.0, 0.5, 1.0,1);
  //std::cout << "painted cloth" << std::endl;
  if (cloth) cloth->Paint(texture_id[2]);
  //if (fluid) fluid->Paint();
  // =========================================================
 // glEndList();
  //display();
  //glutPostRedisplay();
}

// ========================================================
// ========================================================

int HandleGLError() {
  GLenum error;
  int i = 0;
  while ((error = glGetError()) != GL_NO_ERROR) {
    printf ("GL ERROR(%d):  %s\n", i, gluErrorString(error));
    i++;
  }
  if (i == 0) return 1;
  return 0;
}
/*if(topEdge)
	{
		if(direction==2) //left stroke
		{
			if(i==0)//left side of mesh
			{
			cout<<"LLL"<<endl;
				Vertex *va = cloth->getParticle(i,j).vert;
				Vertex *vb = cloth->getParticle(i,j+1).vert;//mesh->getVertex(i*cloth->nx+j+1);
				Vertex *vc = cloth->getParticle(i+1,j+1).vert;//mesh->getVertex((i*(cloth->nx+1))+j+1);
				Edge *ab = mesh->getMeshEdge(va,vb);
				if(j==0) //top left corner
				{
				
				}
				else if(j==cloth->ny-1) // bottom left corner
				{
					
				}
				else // somewhere inbetween
				{
					Vertex *vd = cloth->getParticle(i,j-1).vert;//mesh->getVertex((i*(cloth->nx))+j-1); //top vert of second triangle
					cout<<"LLL"<<endl;
					Edge *ba = mesh->getMeshEdge(vb,va);
					Triangle *t = ab->getTriangle();
					Triangle *t2 = ba->getTriangle();
					mesh->removeTriangle(t);
					//mesh->removeTriangle(t2);
					cout<<"LLL"<<endl;
					//delete va;
					
					//mesh->
				}
				//getTriangle()
			}
			else if(i==cloth->nx-1) //right side of mesh
			{
			
			}
			else //somewhere in the middle
			{
			
			}
		}
		else
		{
			//Vertex *va = cloth->getParticle(i,j).vert;//mesh->getVertex(i*cloth->nx+j);
			//Vertex *vb = cloth->getParticle(i,j-1).vert;//mesh->getVertex(i*cloth->nx+j-1);
			//Edge *ab = mesh->getMeshEdge(va,vb);
			//delete ab;
		}
	}*/

	/*
	vector<pair<int, int> >::iterator p;
	//delete all struc connections to this vertex
	for(unsigned int k=0; k<cloth->getParticle(i,j).struc.size(); k++)
	{
		//ClothParticle cp2=cloth->getParticle(cloth->getParticle(i,j).struc[k].first,cloth->getParticle(i,j).struc[k].second);
		p=find(cloth->getParticle(cloth->getParticle(i,j).struc[k].first,cloth->getParticle(i,j).struc[k].second).struc.begin(), \
		 cloth->getParticle(cloth->getParticle(i,j).struc[k].first,cloth->getParticle(i,j).struc[k].second).struc.end(),make_pair(i,j));
		 
		if(p!=cloth->getParticle(cloth->getParticle(i,j).struc[k].first,cloth->getParticle(i,j).struc[k].second).struc.end())
		{
			cloth->getParticle(cloth->getParticle(i,j).struc[k].first,cloth->getParticle(i,j).struc[k].second).struc.erase(p);//cp2.struc.erase(p);
		}
		
	}
	//cloth->getParticle(i,j).struc.clear();//cp.struc.clear();
	
	for(unsigned int k=0; k<cloth->getParticle(i,j).shear.size(); k++)
	{
		//ClothParticle cp2=cloth->getParticle(cloth->getParticle(i,j).shear[k].first,cloth->getParticle(i,j).shear[k].second);
		p=find(cloth->getParticle(cloth->getParticle(i,j).shear[k].first,cloth->getParticle(i,j).shear[k].second).shear.begin(), \
		 cloth->getParticle(cloth->getParticle(i,j).shear[k].first,cloth->getParticle(i,j).shear[k].second).shear.end(),make_pair(i,j));
		 
		if(p!=cloth->getParticle(cloth->getParticle(i,j).shear[k].first,cloth->getParticle(i,j).shear[k].second).shear.end())
		{
			cloth->getParticle(cloth->getParticle(i,j).shear[k].first,cloth->getParticle(i,j).shear[k].second).shear.erase(p);//cp2.shear.erase(p);
		}
	}
	//cloth->getParticle(i,j).shear.clear();//cp.shear.clear();
	
	for(unsigned int k=0; k<cloth->getParticle(i,j).bend.size(); k++)
	{
		//ClothParticle cp2=cloth->getParticle(cloth->getParticle(i,j).bend[k].first,cloth->getParticle(i,j).bend[k].second);
		p=find(cloth->getParticle(cloth->getParticle(i,j).bend[k].first,cloth->getParticle(i,j).bend[k].second).bend.begin(), \
		 cloth->getParticle(cloth->getParticle(i,j).bend[k].first,cloth->getParticle(i,j).bend[k].second).bend.end(),make_pair(i,j));
		 
		if(p!=cloth->getParticle(cloth->getParticle(i,j).bend[k].first,cloth->getParticle(i,j).bend[k].second).bend.end())
		{
			cloth->getParticle(cloth->getParticle(i,j).bend[k].first,cloth->getParticle(i,j).bend[k].second).bend.erase(p);//cp2.bend.erase(p);
		}
	}
	//cloth->getParticle(i,j).bend.clear();//cloth->getParticle(i,j).bend.clear();
	
	*/
	
	
